\section{设计模式}
\subsection{八大设计原则}
\begin{enumerate}
    \item 依赖倒置原则（DIP）
          \begin{itemize}
              \item  高层模块(稳定)不应该依赖于低层模块（变化），二者都应该依赖于抽象（稳定）
              \item 抽象（稳定）不应依赖于实现细节（变化），实现细节应该依赖于抽象（稳定）
          \end{itemize}
    \item 开闭原则（OCP）
          \begin{itemize}
              \item 对扩展开放，对更改封闭.
              \item 类模块应该是可以扩展，但是不可修改。
          \end{itemize}
    \item 单一职责原则(SRP)
          \begin{itemize}
              \item 一个类应该仅有一个引起它变化的原因。
              \item 变化的方向隐含类的责任。
          \end{itemize}
    \item Liskov替换原则(LSP)
          \begin{itemize}
              \item 子类必须能替换他们的基类(IS-A)
              \item 集成表达类型抽象
          \end{itemize}
    \item 接口隔离原则(ISP)
          \begin{itemize}
              \item  不应该强迫客户程序依赖他们不用的方法
              \item 接口应该小二完备
          \end{itemize}
    \item 接口隔离原则(ISP)
          \begin{itemize}
              \item 不应该强迫客户程序依赖他们不用的方法
              \item 接口应该小二完备
          \end{itemize}
    \item 有限使用对象组合而不是类继承
          \begin{itemize}
              \item 类集成通常为白箱复用，对象组合通常为黑箱复用。
              \item 集成在某种程度上博怀了封装性，子类、父类耦合度过高。而对象组合则只要求被组合对象具有良好的
          \end{itemize}
    \item 封装变化点
          \begin{itemize}
              \item 使用封装来创建对象之间的分界层，让设计者能在分界层的一侧进行修改，而不会对另一侧产生不良的影响。
          \end{itemize}
    \item 针对接口编程而不是针对实现编程
          \begin{itemize}
              \item 不将变量类型声明为某个特定的具体类而是声明为接口。
              \item 客户程序无序获取对象的具体类型，只需要知道对象的接口。
              \item 减少系统中各部分的依赖关系从而实现“高内聚，松耦合”的类型设计方案。
          \end{itemize}
\end{enumerate}
面向对象：
\begin{itemize}
    \item 理解隔离变化：从宏观层面来看，面向对象的构建方式更能适应软件的变化，能将变化所带来的影响减为最小。
    \item 各司其职：从微观层面，面向对象的方式更强调各个类的责任。由于需求变化导致的新增类型不应该影响原来类型的实现--所谓的各负其责。
    \item 对象是什么？
          \begin{itemize}
              \item 从语言实现层面来看，对象封装了代码和数据。
              \item 从规格层面讲，对象是以一列可以背使用的公共接口。
              \item 从概念层面讲，对象是某种拥有责任的抽象。
          \end{itemize}
\end{itemize}
\subsection{模式}
模式分类：
\begin{itemize}
    \item 组件协作类：
          \begin{itemize}
              \item Template Method
              \item strategy
              \item Observer/Event
          \end{itemize}
    \item 单一职责
          \begin{itemize}
              \item Decorator
              \item Bridge
          \end{itemize}
    \item 对象创建：
          \begin{itemize}
              \item Factory Method
              \item Abstract Factory
              \item Prototype
              \item Builder
          \end{itemize}
    \item 对象性能
          \begin{itemize}
              \item Singleton
              \item Flyweight
          \end{itemize}
    \item 接口隔离
          \begin{itemize}
              \item Facade
              \item Proxy
              \item Mediator
          \end{itemize}
    \item 状态变化：
          \begin{itemize}
              \item Memento
              \item State
          \end{itemize}
    \item 数据结构
          \begin{itemize}
              \item Composite
              \item Iterator
              \item Chain of
              \item Resposibility
          \end{itemize}
    \item 行为变化
          \begin{itemize}
              \item Command
              \item Visitor
          \end{itemize}
    \item 领域问题：Interpreter
\end{itemize}
现代软件设计的特征是“需求的频繁变化”。设计模式的要点是“寻找变化点”，然后在变化点处使用设计模式，从而来应对需求的变化。“什么时候，什么地点使用设计模式”比设计模式
结构本身更重要。
\begin{itemize}
    \item 静态绑定 -- 动态绑定。
    \item 早绑定 -- 为晚绑定。
    \item 继承 -- 组合。
    \item 编译时依赖 -- 运行时依赖。
    \item 紧耦合 -- 松耦合。
\end{itemize}
\subsection{组件协作模型}
现代软件专业分工之后对的第一个结果是“框架于应用程序的划分”，“组件协作”模式通过晚绑定来实现框架和应用程序之间的松耦合，是二者之间协作时常用的模式。
\subsubsection{Template Method}
在软件构建过程中，对于某一项任务，它通常有稳定的整体操作结果，但是各个子步骤却有很多改变的需求，或者由于固有的原因（比如框架与应用之间的关系）而无法和任务的整体结构
同时实现。如何在确定稳定操作结构的前提下，来灵活应对各个子步骤的变化或者晚期实现需求？
早绑定：后开发的程序依赖于先开发的程序。例如当我们的程序需要实现基础的数学运算来对数值计算。数值计算库实际上已经有人写好，所以我们新的程序可以直接依赖于旧的程序。晚绑定相反，已经开的的（需求固定不变的部分）依赖于后来设计的应用。
定义一个操作中的算法的骨架（稳定），而将一些步骤（变化）延迟到子类（即：当前结构没法确定部分算法，算法实现交给子类）中。Template Method使得子类可以不改变一个\textbf{算法的结构}即可重定义（Overvide重写）该算法的某些特定步骤。
\begin{figure}[!htbp]
    \centering
    \includegraphics*[width=0.5\textwidth]{templete_method}
    \caption{Template方法的类图}
    \label{fig:templete_method}
\end{figure}
Template Method要点：
\begin{itemize}
    \item Template Method模式是一种非常基础性的设计模式，在面向对象系统中有大量的应用。它用最简洁的机制（虚函数的多态）它为许多应用程序框架提供了灵活的扩展点，是代码服用方面的基本实现结构。
    \item 除了可以灵活应多子步骤的变化外，“不要调用我，让我来调用你”的反向控制结构是Template Method的典型应用。
    \item 具体实现方面，被Template Method调用的虚方法可以具有实现，也可以没有任何实现（抽象方法，纯虚方法），但一般推荐设置为protect方法。
\end{itemize}
\subsubsection{strategy}
在软件构建过程中，某些对象使用的算法可能多种多样，经常改变。如果将这些算法都编码到对象中，将会使得对象变得异常复杂；而有时候支持一些不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对象的算法？将算法和对象本身解藕，从而避免上述问题？
解决了什么问题？
\begin{itemize}
    \item 解决了代码中出现多个if判断条件时候的扩展问题。
    \item 模式定义：定义一系列算法，把他们一个个封装起来，并且使他们可以互相替换（变化）。改模式使得算法可以独立于使用它的客户程序（稳定）而变化（扩展，子类化）。

\end{itemize}
Strategy类通过多态实现动态创建具体的类，然后用通过Strategy类的多态性指向子类的算法。根据需要创建指定对象，然后调用指定对象的方法。
\begin{figure}[!htbp]
    \centering
    \includegraphics*[width=0.5\textwidth]{strategy}
    \caption{Strategy模式}
    \label{fig:strategy}
\end{figure}
要点：
\begin{itemize}
    \item strategy以及其子类为组件提供了一系列可重用的算法，从而可以使得类型在运行时方便的更具需要在各个算法之间进行切换。
    \item strategy模式提供了用条件判断语句判断以外的另一种选择，消除条件判断语句就是在解耦合。含有许多条件判断语句的代码通常都需要strategy模式。
    \item 如果Strategy对象没有实例变量，那么各个上下文可以共享一个stratege对象从而节省对象开销。
\end{itemize}

\subsubsection{观察者模式（observer）}
解决了什么问题：
\begin{itemize}
    \item 在软件构建过程中，我们需要为某些对象创建一种通知依赖关系--一个对象（目标对象）的状态发生改变，所有的依赖对象（观察者对象）都将得到通知。如果这个依赖关系过于紧密，将使软件不能很好的抵御变化。
    \item 使用面向对象技术，可以将这种依赖关系弱化，并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
\end{itemize}
模式定义：定义对象的一种一对多（变化）的依赖关系，以便当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并自动更新。
\begin{itemize}
    \item 使用面向对象的的抽象，观察者模式使得我们可以独立地改变目标与观察者，从而使二者之间的依赖关系达到松耦合。
    \item 目标发送通知时，无需指定观察者，通知（可以携带通知信息作为参数）会自动传播。
    \item 观察者积极决定是否需要订阅通知，目标对象对此一无所知。
    \item 观察则模式是基于事件的ui框架中非常常用的设计模式，也是MVC模式的重要组成部分。
\end{itemize}
\begin{figure}[!htbp]
    \centering
    \includegraphics*[width=0.5\textwidth]{observer}
    \caption{观察者模式}
    \label{fig:observer}
\end{figure}
\subsection{单一职责模式}
在软件组件的设计中。如果责任划分的不清晰，使用继承得到的结果往往是随需求的变化，子类急剧膨胀，同时充斥着重复代码，这时候的关键是划清责任。
\subsubsection{Decrator}
假设这样一个场景：我们需要实现对文件，网络，内存数据进行读、写、查询操作。同时我们需要对这些数据进行加密操作和缓存操作。我们可以这样实现：
\begin{figure}[!htbp]
    \centering
    \includegraphics*[width=0.5\textwidth]{decrator1}
    \caption{操作示意图}
    \label{fig:decrator1}
\end{figure}
我们实现了抽象类Stream，然后通过抽象类实现了FileStream（文件操作）、NetworkStream（网络操作）、MemoryStream（内存操作），然后我们针对
不同的流实现各自不同的加密操作CryptoFileStream、CryptoNetworkStream、CryptoMemoryStream。同时我们需要对流数据缓存，我们实现了对不同流的缓存：
BufferedFileStream、BufferedNetworkStream、BufferedMemoryStream。这样做的缺点是对象创建非常多。
\begin{figure}[!htbp]
    \centering
    \includegraphics*[width=0.5\textwidth]{decrator2}
    \caption{Decrator改进操作示意图}
    \label{fig:decrator2}
\end{figure}
通过改进之后我们可以单独获得不同的流对象，如果我们需要对不同的流加密或者缓存，可以传Stream对象通过多态指向不同的流进行操作或者加密。
\begin{itemize}
    \item 通过采用组合而不是继承的手法，装饰器模式实现了在运行时动态扩展对象功能的能力，而且可以更具需要扩展多个功能。避免了使用继承带来的灵活性差和多子类衍生问题。
    \item 装饰器类在接口上表现为is-a component的继承关系，即装饰器类继承了component类所具有的接口。但在实现上有表现为has-a component的组合关系，即decorator类有使用了另外一个component类。
    \item 装饰器模式的目的并不是解决多子类延伸到个多继承问题，装饰器模式应用的要点在于解决主体类在多个方向上的扩展功能--是为装饰的含义。
\end{itemize}
装饰器的类图如\figref{decrator}
\begin{figure}[!htbp]
    \centering
    \includegraphics*[width=0.5\textwidth]{decrator}
    \caption{装饰器}
    \label{fig:decrator}
\end{figure}
\subsection{Bridge模式}
Bridge模式使用对象间的组合关系解耦了抽象和实现之间的固有绑定关系，使得抽象和实现可以沿着各自的维度来变化，所谓抽象和实现沿着各自维度变化，即“子类化”他们。Bridge模式有时候类似于多继承方案，但是多继承往往违背单一职责原则（即一个类只有一个变化原因），复用性较差。Bridge模式是比多继承方案更好的解决方案。Bridge模式的应用一般在两个非常强的变化唯独。优势一个类也有多余两个的变化维度，这是可以使用Bridge的扩展模式。
% ## 对象创建模式
% - Factory Method
% - Abstract Factory
% - Prototype
% - Builder
% ## Factory Method
% 定义一个用于创建对象的接口，让子类决定实例化哪个类。Factory Method使得一个类额实例化延迟（目的：解藕，手段：虚函数）到子类
%  - factory method模式用于隔离类uixiangde使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型，紧耦合（new创建对象）会导致软件的脆弱。
%  - FactoryMethod模式通过面向对象的手法，将所要创建的具体对象工作延迟到子类，从而实现一种扩展的策略，较好地解决了这种紧耦合关系。
%  - Factory Metho模式解决单个对象的需求变化。缺点在于要创建方法/参数相同。
% ## Builder构造器模式
% 将对象的表示和对象的构造分离，使得同样的构造过程（稳定）可以创建不同的表示（变化）
% - Builder模式主要用于分步骤构建一个复杂的对象，在其中分步骤是一个稳定的算法，而复杂部分的各个对象经常变化。
% - 变化点在哪，封装哪里--builder模式主要应用于复杂对象各个部分的频繁需求变动。其缺点在于难以应对分步骤构建算法的需求变动。
% - builder模式中，要注意不同语言中构造器调用虚函数的差别。
% ## 对象性能模式
% 面向对象很好的解决了抽象的问题，但是必不可少的付出了一定的代价。对于通常情况来讲，面向对象的成本都可以互略不急。但是默写情况下，面向对象带来的成本必须谨慎处理。
% 典型的模式有：
% 1. Singleton
% 2. Flyweight

% ### Singleton（单例模式）
% 在软件系统中，京城有这样一些特殊的类，必须保证他们在系统中只存在一个实例，才能保证他们的逻辑正确性一级良好的效率。

% 双检查锁存在的问题：
% ```
% // 双检查锁，但是由于内存读写recorder不安全
% Singleton* Singleton::getInstance() {
%     if(m_instance == nullptr){
%         Lock lock;
%         if(m_instance == nullptr){
%             m_instance = new Singleton();
%         }
%     }
%     return m_instance;
% }
% ```
% 对于`m_instance = new Singleton();`一般认为是这么三个步骤：
% 1. 创建一块内存区域
% 2. 调用构造体创建对象获取对象的地址。
% 3. 将对象的地址赋值给m_instance

% 实际上编译器可能会对这些步骤调整以实现优化：
% 1. 创建内存区域
% 2. 将内存地址给构造器
% 3. 调用构造器
% 多线程环境下可能出现返回`m_instance`的时候构造器还没有构造对象，返回的是一块指针而已，没有对象在其指向的位置。

% - Singleton模式中的实例构造器可以设置为protected以允许子类派生。
% - Singleton模式一般不需要支持拷贝构造函数和Clone接口，因为这有可能导致多个对象实例，与Singleton模式的初衷违背。
% - 如何实现多线程环境下安全的Singleton？注意对双检查锁的正确实现。

% ### FlyWeight模式
% 运用共享技术有效支持大量细粒度的对象。假设创建一个font对象。
% 常见的面向对象方法,通过创建对象池，创建对象的时候优先从对象池里面查找对象然后找到了就返回，没有找到就创建对象然后添加到对象池。通过缓存对象的形式减小大量对象创建的开销。
% ```
% class FontFactory{
% private:
%     map<string,Font*> fontPool;
% public:
%     Font* GetFont(const string& key){
%         map<string,Font*>::iterator iter = fontPool.find(key);
%        if(item!=fontPool.end()){
%             return fontPool[key]
%     }else{
%         Font* font = new Font(key);
% fontPool[key] = font;
% return font;
%     }
% }
% }
% ```
% - 面向对象很好的解决了抽象性的问题，但是作为一个运行在机器中的程序实体，我们需要考虑对象的代价问题。FlyWeight主要解决面向对象的代价问题，一般不触及面向对现代个抽象性问题。
% - Flyweight采用对象共享的做法来降低系统中对象的个数，从而降低犀利读对象给系统来带的内存压力。在具体实现方面，要注意对象状态的处理。
% ## 接口隔离模式
% - 门面模式
% - 代理模式
% - 适配器模式
% - 
% 在组建构建过程中，某些接口之间直接的依赖通常会带来很多问题，甚至根本无法实现。采用添加一层间接（稳定）接口来隔离本来互相紧密关联的接口是一种常见的解决方案。
% ### 门面模式
% 为子系统中的一组接口提供一个一致（稳定）的界面，门面模式定义了一个高层接口，这个接口使得这一子系统更加容易使用（复用）。
% - 从客户程序的角度看，门面模式简化了整个组件系统的接口，对于组建内部与外部客户程序来说，达到了一种“解藕”的效果——内部子系统的任何变化不会影响到门面接口的变化。
% - 门面设计模式更注重架构的层次去看整个系统，而不是单个类的层次。门面模式很多时候更是一种架构设计模式。
% - 门面设计模式并不是一个集装箱，可以任意放进任意多个对象。门面模式中组建内部应该是“相互耦合关系比较大的一系列组件”，而不是一个简单的功能集合。
